﻿using System.Collections.Generic;
using UnityEngine;
using System.Collections;

namespace MyLib
{
    /// <summary>
    /// 玩家自己的属性 从服务器上同步 
    /// </summary>
    public class MySelfAttributeSync : MonoBehaviour
    {
        private AvatarInfo curInfo;
        private NpcAttribute attr;
        private LogicCommand logicCommand;//操作MoveController 类似于服务器控制位置移动命令而不是客户端控制移动
        private AICharacter ai;
        void Start()
        {
            logicCommand = GetComponent<LogicCommand>();
            curInfo = AvatarInfo.CreateBuilder().Build();
            attr = GetComponent<NpcAttribute>();
            ai = GetComponent<AIBase>().GetAI();
            //StartCoroutine(SyncServerPos());
        }

        /// <summary>
        /// 客户端控制优先级低于服务器的位置控制优先级
        /// </summary>
        /// <returns></returns>
        IEnumerator SyncServerPos()
        {
            yield return new WaitForSeconds(2);
            var wt = new WaitForSeconds(0.1f);
            //var ai = GetComponent<AIBase>().GetAI();

            while (true)
            {
                if (ai.state.type != AIStateEnum.DEAD)
                {
                    SendMoveCmd();
                }
                yield return wt;
            }
        }

        private void SendMoveCmd()
        {
            if (!curInfo.HasX)
            {
                return;
            }
            var lag = NetworkLatency.LatencyTime;
            var fPos = NetworkUtil.FloatPos((int)(curInfo.X), curInfo.Y, (int)(curInfo.Z));
            var difPos = Util.XZSqrMagnitude(fPos, transform.position);

            //延迟大的情况下增加误差容忍度 100是unity 1m 延迟和对应的物理距离应该是线性的
            var n = (lag/0.05f);
            n *= n;
            if (ai.state.type != AIStateEnum.MOVE_SHOOT)
            {
                n = 1;
            }
            var checkDist = Mathf.Min(Mathf.Max(2, 2*n), 64);
            if (difPos > 64)
            {
                var floatPos = NetworkUtil.FloatPos(curInfo.X, curInfo.Y, curInfo.Z);
                //this.rigidbody.MovePosition(floatPos);
                Util.ForceResetPos(this.GetComponent<Rigidbody>(), floatPos);
                //Util.ShowMsg("FixPos: "+(int)(difPos*100));
            }
            else if (difPos > checkDist)
            {
                //Util.ShowMsg("FarPos: "+(int)(difPos*100)+" cd "+(int)(checkDist*100));
                var mvTarget = new Vector3(curInfo.X / 100.0f, curInfo.Y / 100.0f + 0.2f, curInfo.Z / 100.0f);
                var cmd = new ObjectCommand();
                cmd.targetPos = mvTarget;
                cmd.UseDir = false;
                cmd.UseY = false;
                cmd.commandID = ObjectCommand.ENUM_OBJECT_COMMAND.OC_MOVE;
                logicCommand.PushCommand(cmd);
            }
        }

    
        public void NetworkAttribute(AvatarInfo info) {
            var attr = GetComponent<NpcAttribute>();
            Log.Net("MySelfSync: "+info);
            if (info == null)
            {
                Debug.LogError("NetMatchInfo is Null ");
                return;
            }

            if (info.HasX)
            {
                var lag = NetworkLatency.LatencyTime;
                var predictLag = Mathf.Max(lag*2, 0.1f);

                curInfo.SpeedX = info.SpeedX;
                curInfo.SpeedY = info.SpeedY;
                curInfo.X = (int)(info.X+info.SpeedX*predictLag);
                curInfo.Y = info.Y;
                curInfo.Z = (int)(info.Z+info.SpeedY*predictLag);
                curInfo.Dir = info.Dir;
            }

            if(info.HasTeamColor) {
                attr.SetTeamColorNet(info.TeamColor);
            }
            if(info.HasIsMaster) {
                attr.SetIsMasterNet(info.IsMaster);
            }

            var dataChanged = false;
            var skillCount = curInfo.KillCount;
            if (info.HasKillCount)
            {
                skillCount = info.KillCount;
                curInfo.KillCount = info.KillCount;
                dataChanged = true;
            }

            var deadCount = curInfo.DeadCount;
            if (info.HasDeadCount)
            {
                deadCount = info.DeadCount;
                curInfo.DeadCount = info.DeadCount;
                dataChanged = true;
            }

            var secondaryAttackCount = curInfo.SecondaryAttackCount;
            if (info.HasSecondaryAttackCount)
            {
                secondaryAttackCount = info.SecondaryAttackCount;
                curInfo.SecondaryAttackCount = info.SecondaryAttackCount;
                dataChanged = true;
            }

            if (info.HasScore)
            {
                curInfo.Score = info.Score;
                dataChanged = true;
            }

            if (dataChanged)
            {
                var sid = attr.GetNetView().GetServerID();
                ScoreManager.Instance.NetSyncScore(sid, curInfo.Score, sid, skillCount, deadCount, secondaryAttackCount);
            }

            if (info.HasContinueKilled)
            {
                curInfo.ContinueKilled = info.ContinueKilled;
                if (curInfo.ContinueKilled > 0)
                {
                    //ScoreManager.Instance.PlayerKillSound(curInfo.ContinueKilled);
                }
            }
            if (info.HasSkillAction)
            {
                info.SkillAction.X = curInfo.X;
                info.SkillAction.Y = curInfo.Y;
                info.SkillAction.Z = curInfo.Z;
                info.SkillAction.Dir = curInfo.Dir;
                this.NetworkAttack(info.SkillAction);
            }
        }

        public void NetworkAttack(SkillAction sk)
        {
            var cmd = new ObjectCommand(ObjectCommand.ENUM_OBJECT_COMMAND.OC_USE_SKILL);
            cmd.skillId = sk.SkillId;
            cmd.skillLevel = sk.SkillLevel;
            cmd.staticShoot = sk.IsStaticShoot;
            cmd.targetPos = NetworkUtil.FloatPos(sk.X, sk.Y, sk.Z);
            cmd.dir = sk.Dir;
            cmd.skillAction = sk;

            Log.GUI("My Player Attack LogicCommand");
            gameObject.GetComponent<LogicCommand>().PushCommand(cmd);
            
        }

        public void NetworkBuff(GCPlayerCmd cmd)
        {
            var sk = Util.GetSkillData(cmd.BuffInfo.SkillId, 1);
            var skConfig = SkillLogic.GetSkillInfo(sk);
            var evt = skConfig.GetEvent(cmd.BuffInfo.EventId);
            var binfo = cmd.BuffInfo;
            if (evt != null)
            {
                var pos = cmd.BuffInfo.AttackerPosList;
                var px = pos[0]/100.0f;
                var py = pos[1]/100.0f;
                var pz = pos[2]/100.0f;
                gameObject.GetComponent<BuffComponent>()
                    .AddBuff(evt.affix, new Vector3(px, py, pz), 0, cmd.BuffInfo.BuffId);
            }
        }

        public void NetworkRemoveBuff(GCPlayerCmd cmd)
        {         
            var binfo = cmd.BuffInfo;
            if (binfo.HasBuffType)
            {
                gameObject.GetComponent<BuffComponent>().RemoveBuff((Affix.EffectType) binfo.BuffType);
            }
            else
            {
                gameObject.GetComponent<BuffComponent>().RemoveBuffId( binfo.BuffId);
            }

        }
    }
}